package br.com.odontosul.atendimento;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import br.com.odontosul.entity.Atendimento;
import br.com.odontosul.util.ArquivoUtil;

import com.lowagie.text.DocumentException;
import com.lowagie.text.pdf.AcroFields;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;

/**
 * Esta classe imprime no template PDF as informacoes do darf. 
 * 
 * @version 1
 */
public class VisualizadorPDF {
	//private static Logger logger = new Logger(VisualizadorPDF.class);
	
	private static URL TEMPLATE = VisualizadorPDF.class.getResource("/resources/templates/fichaAtendimento.pdf");

	private PdfReader reader;
	private PdfStamper stamper;
	private AcroFields form;
	private ByteArrayOutputStream outputStream;
	private Atendimento atendimento;
	private File template;

	//DataHoraUtil hora = new DataHoraUtil();
	
	/**
	 *<p> Para uso interno do componente </p> 
	 */
	VisualizadorPDF() {
		
	}
	
	VisualizadorPDF(Atendimento atendimento) {
		this.atendimento = atendimento;
	}
	
	public VisualizadorPDF(Atendimento atendimento, File template) {
		this.atendimento = atendimento;
		
		setTemplate(template);
	}

	/**
	 * <p>
	 * Agrupa todos boletos em um arquivo.
	 * </p>
	 * 
	 * @param pathName arquivo de destino
	 * @param boletos a serem agrupados
	 * @param boletoViewer visualizador
	 * @return File contendo boletos gerados
	 * 
	 * @throws JRimumException Quando ocorrer um problema na geracao do PDF que esta fora do controle
	 * da biblioteca.
	 * 
	 * @since 0.2
	 */
	protected static File agruparEmUmPDF(String pathName, List<Atendimento> atendimentos, GeradorAtestado boletoViewer) {
		File arq = null;

		List<byte[]> boletosEmBytes = new ArrayList<byte[]>(atendimentos.size());

		for (Atendimento bop : atendimentos) {
			boletosEmBytes.add(boletoViewer.setBoleto(bop).getPdfAsByteArray());
		}

		return arq;
	}

	/**
	 * <p>
	 * SOBRE O MÉTODO
	 * </p>
	 * 
	 * @param path
	 * @param extensao 
	 * @param boletos
	 * @return List<File> com os boletos gerados.
	 * 
	 * @since 0.2
	 */
	/*protected List<File> umPorPDF(String path, String extensao, List<Atendimento> boletos) {
		List<File> arquivos = new ArrayList<File>(boletos.size());
		//int cont = 1;
		String strBanco = "";
		
		for (Atendimento bop : atendimentos) {
			if (strBanco.equals(""))
				strBanco = "_" + bop.getCedente().getContaBancaria().getBanco().name() + "_";
			
			darf = bop;
			//arquivos.add(getFile(path + "/Darf" + strBanco + cont++ + extensao));
			arquivos.add(getFile(path + "/Darf" + strBanco + bop.getNumeroReferencia() + extensao));
		}

		return arquivos;
	}*/

	/**
	 * Retorna o PDF como File
	 * @param pathName
	 * @return
	 * @throws IllegalArgumentException
	 */
	protected File getFile(String pathName) {
		File file = null;

		try {
			processarPdf();
			
			//file = ArquivoUtil.bytes2File(pathName, outputStream.toByteArray());
			
		} catch (FileNotFoundException e) {
			//logger.error("Erro ao tentar acessar arquivo inexistente. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro ao tentar acessar arquivo inexistente: [" + pathName + "]. " +
					"Causado por " + e.getLocalizedMessage(), e);
			
		} catch (IOException e) {
			//logger.error("Erro durante a criação do arquivo. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro durante a criação do arquivo: [" + pathName + "]. " +
					"Causado por " + e.getLocalizedMessage(), e);
			
		} catch (DocumentException e) {
			//logger.error("Erro durante a criação do arquivo. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro durante a criação do arquivo: [" + pathName + "]. " +
					"Causado por " + e.getLocalizedMessage(), e);
		}
		
		return file;
	}

	/**
	 * Retorna o PDF em Stream
	 * 
	 * @return
	 */
	protected ByteArrayOutputStream getStream() {
		ByteArrayOutputStream baos = null;
		
		try {
			processarPdf();
			
			//baos = ArquivoUtil.bytes2Stream(outputStream.toByteArray());
			
		} catch (IOException e) {
			//logger.error("Erro durante a criação do stream. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro durante a criação do stream. " +
					"Causado por " + e.getLocalizedMessage(), e);
			
		} catch (DocumentException e) {
			//logger.error("Erro durante a criação do stream. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro durante a criação do stream. " +
					"Causado por " + e.getLocalizedMessage(), e);
		}
		
		return baos;
	}

	/**
	 * Retorna o PDF em array de bytes.
	 * 
	 * @return
	 */
	protected byte[] getBytes() {
		byte[] bytes = null;
		
		try {
			processarPdf();
			bytes = outputStream.toByteArray();
			
		} catch (IOException e) {
			//logger.error("Erro durante a criação do stream. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro durante a criação do stream. " +
					"Causado por " + e.getLocalizedMessage(), e);
			
		} catch (DocumentException e) {
			//logger.error("Erro durante a criação do stream. " + e.getLocalizedMessage(), e);
			throw new AtestadoExcecao("Erro durante a criação do stream. " +
					"Causado por " + e.getLocalizedMessage(), e);
		}
		
		return bytes;
	}

	protected File getTemplate() {
		return template;
	}

	protected void setTemplate(File template) {
		this.template = template;
	}

	protected void setTemplate(String pathname) {
		setTemplate(new File(pathname));
	}

	/**
	 * @return the darf
	 * 
	 * @since 0.2
	 */
	protected Atendimento getAtendimento() {
		return this.atendimento;
	}
	
	/**
	 * <p>
	 * SOBRE O MÉTODO
	 * </p>
	 * 
	 * @throws IOException
	 * @throws DocumentException
	 * 
	 * @since
	 */
	private void processarPdf() throws IOException, DocumentException {
		inicializar();
		preencher();
		finalizar();
	}

	/**
	 * <p>
	 * SOBRE O MÉTODO
	 * </p>
	 * 
	 * @return URL template
	 * 
	 * @since
	 */
	
		private URL getTemplateFromResource() {
		URL templateFromResource = null;

		//if (atendimento != null) {
			templateFromResource = TEMPLATE;
		//}
		return templateFromResource;
	}

	/**
	 * <p>
	 * Verifica se o template que será utilizado virá do resource ou é externo,
	 * ou seja, se o usuário definiu ou não um template.
	 * </p>
	 * 
	 * @return true caso o template que pode ser definido pelo usuário for null;
	 *         false caso o usuário tenha definido um template.
	 * 
	 * @since
	 */
	private boolean isTemplateFromResource() {
		return getTemplate() == null;
	}

	/**
	 * <p>
	 * SOBRE O MÉTODO
	 * </p>
	 * 
	 * @throws IOException
	 * @throws DocumentException
	 * 
	 * @since
	 */

	private void inicializar() throws IOException, DocumentException {
		if (isTemplateFromResource()) {
			reader = new PdfReader(getTemplateFromResource());
		} else {
			reader = new PdfReader(getTemplate().getAbsolutePath());
		}

		outputStream = new ByteArrayOutputStream();
		stamper = new PdfStamper(reader, outputStream);
		form = stamper.getAcroFields();
	}

	/**
	 * <p>
	 * SOBRE O MÉTODO
	 * </p>
	 * 
	 * @throws DocumentException
	 * @throws IOException
	 * 
	 * @since
	 */
	private void finalizar() throws DocumentException, IOException {

		reader.consolidateNamedDestinations();/*
												 * Replaces all the local named
												 * links with the actual
												 * destinations.
												 */

		stamper.setFormFlattening(true);/*
										 * Determines if the fields are
										 * flattened on close.
										 */
		stamper.setRotateContents(true);/*
										 * Flags the content to be automatically
										 * adjusted to compensate the original
										 * page rotation.
										 */

		reader.removeFields();/* Removes all the fields from the document. */

		stamper.setFullCompression();/*
										 * Sets the document's compression to
										 * the new 1.5 mode with object streams
										 * and xref streams.
										 */

		reader.eliminateSharedStreams();/*
										 * Eliminates shared streams if they
										 * exist.
										 */

		// Send immediately
		outputStream.flush();

		// close All in this order
		outputStream.close();
		reader.close();
		stamper.close();
	}

	/**
	 * <p>
	 * SOBRE O MÉTODO
	 * </p>
	 * 
	 * @throws MalformedURLException
	 * @throws IOException
	 * @throws DocumentException
	 * 
	 * @since
	 */
	private void preencher() throws MalformedURLException, IOException, DocumentException {
		
		//setNumeroControle();
	
	}

	/*private void setNumeroControle() throws IOException, DocumentException {
		if (atendimento.getNome() != null) {
			form.setField("numeroControle", String.format("%09d", atendimento.getAtestado().getId())+"/2012");
		}
	}*/
	
	/**
	 * Exibe os valores de instancia.
	 * 
	 */
	/*@Override
	public String toString() {
		ToStringBuilder tsb = new ToStringBuilder(this);
		tsb.append(atendimento);
		return tsb.toString();
	}*/
}
